
package com.ctyon.watchsdk.client;

import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.ctyon.watchsdk.model.Watch;
import com.ctyon.watchsdk.protobuf.WatchMessage;
import com.ctyon.watchsdk.task.WatchTask;

import java.util.concurrent.TimeUnit;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

import static com.ctyon.watchsdk.contain.MsgContainer.MSG_USER_BUSINESS;
import static com.ctyon.watchsdk.contain.MsgContainer.MSG_USER_HEART_BEAT;
import static com.ctyon.watchsdk.contain.MsgContainer.MSG_USER_MESSAGE_SUCCESS;
import static com.ctyon.watchsdk.contain.MsgContainer.MSG_USER_TIME_OUT;
import static com.ctyon.watchsdk.contain.MsgContainer.MSG_USER_UP_LINE;


/**
 * @Title: NettyClientHandler
 * @Description: 客户端业务逻辑实现
 * @Version:1.0.0
 */
public class ClientHandler extends ChannelInboundHandlerAdapter {

    private static final String TAG = "NettyClientHandler";

    /**
     * 服务端与客户端连接建立
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Log.d(TAG, "handlerAdded");
        super.handlerAdded(ctx);
    }

    /**
     * 有连接断开
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Log.d(TAG, "handlerRemoved");
        WatchTask.getInstance().releaseChannel();
        super.handlerRemoved(ctx);
    }

    /**
     * 连接处于活动状态
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Log.d(TAG, "channelActive");
        String watchId = WatchTask.getInstance().getOption().getMeid();
        Watch watch = new Watch();
        watch.setMeid(watchId);
        WatchMessage.Msg onLineMsg = WatchMessage.Msg.newBuilder()
                .setMsgType(MSG_USER_UP_LINE)
                .setWatchId(watchId)
                .setContent(JSON.toJSONString(watch))
                .build();
        WatchTask.getInstance().sendNettyMsg(onLineMsg);
        super.channelActive(ctx);
    }

    /**
     * 连接关闭
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Log.d(TAG, "channelInactive");
        //使用过程中断线重连
        final EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(() -> WatchTask.getInstance().reConnect(),2, TimeUnit.SECONDS);
        super.channelInactive(ctx);
    }

    /**
     * 超时处理
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
        Log.d(TAG, "userEventTriggered");
        if (obj instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) obj;
            if (IdleState.WRITER_IDLE.equals(event.state())) { // 如果写通道处于空闲状态，发送心跳命令
                Log.d(TAG, "ping >>> ");
                WatchMessage.Msg pingNettyMsg = WatchMessage.Msg.newBuilder()
                        .setMsgType(MSG_USER_HEART_BEAT)
                        .build();
                WatchTask.getInstance().sendNettyMsg(pingNettyMsg);
            }else if (IdleState.READER_IDLE.equals(event.state())){ // 如果读通道处于空闲状态，心跳命令没收到回复
                Log.d(TAG, "心跳回复超时");
                throw new RuntimeException("发送心跳后15s没有收到心跳回复");
            }
        }
        super.channelInactive(ctx);
    }

    /**
     * 异常处理
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Log.d(TAG, "exceptionCaught : 出现异常 " + cause);
        super.exceptionCaught(ctx, cause);
    }

    /**
     * 业务逻辑处理
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();
        Log.d(TAG, "收到 " + channel.remoteAddress() + "发来的消息");

        try {
            if (msg instanceof WatchMessage.Msg) {
                WatchMessage.Msg watchMsg = (WatchMessage.Msg) msg;
                Log.d(TAG, "内容 " + watchMsg.toString());
                int type = watchMsg.getMsgType();
                if (type == MSG_USER_HEART_BEAT) {
                    Log.d(TAG, " <<< peng");
                    WatchTask.getInstance().callbackPeng();
                }
                else if (type == MSG_USER_UP_LINE) {
                    Log.d(TAG, "上线返回消息");

                }
                else if (type == MSG_USER_TIME_OUT) {
                    Log.d(TAG, "Time Out !!!");
                    WatchTask.getInstance().callbackTimeOut();
                }
                else if (type == MSG_USER_MESSAGE_SUCCESS) {
                    Log.d(TAG, "发送成功");
                    WatchTask.getInstance().callbackFeed(watchMsg.getCmd());
                }
                else if (type == MSG_USER_BUSINESS) {
                    Log.d(TAG, "业务消息 : " + watchMsg.getMsgType());
                    ClientMessage clientMessage = new ClientMessage(watchMsg.getCmd(), watchMsg.getManagerId(), watchMsg.getWatchId(), watchMsg.getContent());
                    WatchTask.getInstance().callbackReceive(clientMessage);
                }
                else {
                    Log.d(TAG, "未知命令");
                    WatchTask.getInstance().callbackUnknownMsg(msg);
                }
            } else {
                Log.d(TAG, "无效消息");
            }
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

}

